﻿/**
  *FileName:    zeigen
  *Date:        23/3/26 周日 上午 12:05:55
  *Author:      Zhou Hang
  *Version:     1.0
  *Description: 一个包含最小功能的线性代数库，对Eigen的拙劣模仿
*/

#pragma once
#include <vector>
#include <stdexcept>
#include <iostream>
#include <iomanip>
#include "config.h"
#include "common.h"
#include <assert.h>
#include <initializer_list>

namespace ZEigen {
class VectorXf;

class MatrixXf {
public:
	explicit MatrixXf() {}
	explicit MatrixXf(std::vector<std::vector<float> > m);

	/*
	 * @brief 矩阵 乘 矩阵
	 * @param m2 待乘的矩阵
	 * @retval 结果矩阵
	 */
	MatrixXf operator*(const MatrixXf& m2);

	friend std::ostream& operator<<(std::ostream& out, MatrixXf& m);

public:
	// getter/setter
	int getCol() const { return this->c; }
	int getRow() const { return this->r; }
	float getItem(int i, int j) const { 
		return this->m[i][j]; 
	}
	void setItem(int x, int y, float item);
	void setMatrix(std::vector<std::vector<float> > m) {
		this->r = m.size();
		this->c = m[0].size();
		this->m = m;
	}

private:
	std::vector<std::vector<float> > m;
	int r, c;
};

class VectorXf : public MatrixXf {
public:
	VectorXf() {}

	explicit VectorXf(std::vector<float> v) {
		this->setVector(v);
	}
	
	/*
	 * @brief 对一个点进行三维扩展, 方便进行二维变换
	 * @param p POINT类型的点
	 * @retval
	 */
	explicit VectorXf(POINT p) {
		std::vector<float> p_vector({ static_cast<float>(p.x), static_cast<float>(p.y), 1});
		this->setVector(p_vector);
	}

public:
	/*
	 * @brief 向量 乘 矩阵
	 * @param m 待乘的矩阵
	 * @retval 结果还是向量
	 */
	VectorXf operator*(MatrixXf& m);

	/* 向量虽然使用列向量存储，但是输出时是行向量形式 */
	friend std::ostream& operator<<(std::ostream& out, VectorXf& v);

public:
	// getter/setter
	int getRow() const { 
		return MatrixXf::getRow(); 
	}
	float getItem(int i) const { 
		return MatrixXf::getItem(i, 0);
	}

	/*
	 * @brief 将给定的向量设置为列向量存入矩阵中
	 * @param
	 * @retval
	 */
	void setVector(std::vector<float> v) {
		std::vector<std::vector<float> > matrix;
		for (float f : v) {
			std::vector<float> row;
			row.push_back(f);
			matrix.push_back(row);
		}
		this->setMatrix(matrix);
	}
};


/*
 * 无效矩阵
 */
class Empty3f : public MatrixXf
{
public:
	Empty3f();
};

/*
 * 旋转矩阵, 绕某点旋转
 */
class Rotate3f : public MatrixXf
{
public:
	Rotate3f(int angle = 45, int cx = 0, int cy = 0);
private:
};

/* 
 * 缩放矩阵
 */
class Scale3f : public MatrixXf
{
public:
	Scale3f(float sx = 1, float sy = 1);
};

/* 
 * 平移矩阵
 */
class Translation3f : public MatrixXf
{
public:
	Translation3f(int tx = 0, int ty = 0);
};

/*
 * 相对任意一条线的对称变换
 */
class Symmetry3f : public MatrixXf
{
public:
	Symmetry3f(float A, float B, float C);
	Symmetry3f(POINT start, POINT end);
private:
	void constructorHelper(float A, float B, float C);
};

/* ============================= 常用变换的简化使用 ============================= */

/*
 * @brief 将一系列变换方法合并为同一个矩阵
 * @param matrixes 用大括号括起来的一系列变换，例如{Translation3f(3, 1), Scale3f(1.2, 4)}
 * @retval 最终融合成的变换矩阵
 */
MatrixXf ComposingTransform(std::initializer_list<MatrixXf> matrixes);

/*
 * @brief 对某个点执行一个变换
 * @param trans 一个变换类
 * @param p 待变换的点
 * @retval 经过一个变换得到的点
 */
POINT TransformPoint(MatrixXf trans, POINT p);

/*
 * @brief 对某个点执行一系列变换
 * @param matrixes 用大括号括起来的一系列变换，例如{Translation3f(3, 1), Scale3f(1.2, 4)}
 * @param p 待变换的点
 * @retval 经过一系列变换得到的点
 */
POINT TransformPoint(std::initializer_list<MatrixXf> matrixes, POINT p);


/*
 * @brief 对一系列点执行一个变换
 * @param trans 一个变换类
 * @param ps 待变换的点集合
 * @retval 经过一个变换得到的点集
 */
std::vector<POINT> TransformPoints(MatrixXf trans, std::vector<POINT> ps);

/*
 * @brief 对一系列点执行一系列变换
 * @param trans 一个变换类
 * @param ps 待变换的点集合
 * @retval 经过一系列变换得到的点集
 */
std::vector<POINT> TransformPoints(std::initializer_list<MatrixXf> matrixes, std::vector<POINT> ps);

/*
 * @brief 对某个点连续做多次变换计算
 * @param trans 一个变换类
 * @param times 连续做的变换次数
 * @param p 待变换的点
 * @retval 变换过程中得到的所有点
 */
std::vector<POINT> SeqTransformPoint(MatrixXf trans, int times, POINT p);
}
